﻿using System;
using System.ComponentModel;
using System.Reflection;
using CoreGraphics;
using MaterialControls;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Moven.Controls;
using Moven.iOS.Renderers;

[assembly:ExportRenderer(typeof(MaterialViewCell), typeof(MaterialViewCellRenderer))]

namespace Moven.iOS.Renderers
{
    public class MaterialViewCellRenderer: CellRenderer
    {
        public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
        {
            var viewCell = (MaterialViewCell)item;
            var cell = reusableCell as ViewTableCell;
            if (cell == null)
                cell = new ViewTableCell(item.GetType().FullName);
            else
                cell.ViewCell.PropertyChanged -= ViewCellPropertyChanged;
            viewCell.PropertyChanged += ViewCellPropertyChanged;
            cell.ViewCell = viewCell;
            typeof(CellRenderer).CallStaticMethod("SetRealCell", BindingFlags.NonPublic, item, cell);
            WireUpForceUpdateSizeRequested(item, cell, tv);
            UpdateBackground(cell, item);
            UpdateIsEnabled(cell, viewCell);
            return cell;
        }

        static void UpdateIsEnabled(ViewTableCell cell, ViewCell viewCell)
        {
            cell.UserInteractionEnabled = viewCell.IsEnabled;
            cell.TextLabel.Enabled = viewCell.IsEnabled;
        }

        void ViewCellPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var viewCell = (MaterialViewCell)sender;
            var realCell = typeof(CellRenderer).CallStaticMethod<ViewTableCell>("GetRealCell", BindingFlags.NonPublic, viewCell);
            if (e.PropertyName != Cell.IsEnabledProperty.PropertyName)
                return;
            UpdateIsEnabled(realCell, viewCell);
        }

        internal class ViewTableCell : MDTableViewCell, INativeElementView
        {
            WeakReference<IVisualElementRenderer> _rendererRef;
			MaterialViewCell _viewCell;

            public MaterialViewCell ViewCell
            {
                get
                {
                    return _viewCell;
                }
                set
                {
                    if (_viewCell == value)
                        return;
                    UpdateCell(value);
                }
            }

            Element INativeElementView.Element => ViewCell;

            internal bool SupressSeparator { get; set; }

            public ViewTableCell(string key)
              : base(UITableViewCellStyle.Default, key)
            {
				AddGestureRecognizer(new UILongPressGestureRecognizer((UILongPressGestureRecognizer recognizer) =>
				{
					if (recognizer.State == UIGestureRecognizerState.Began && _viewCell.LongPressCommand != null && _viewCell.LongPressCommand.CanExecute(null))
					{
						_viewCell.LongPressCommand.Execute(null);
					}
				}));
            }

            public override void LayoutSubviews()
            {
                base.LayoutSubviews();
                if (SupressSeparator && Accessory == UITableViewCellAccessory.None)
                {
                    CGRect frame = Frame;
                    ContentView.Bounds = new CGRect(frame.Location, new CGSize(frame.Width, frame.Height + 0.5f));
                }
                CGRect frame1 = ContentView.Frame;
                View view = ViewCell.View;
                Layout.LayoutChildIntoBoundingRegion(view, frame1.ToRectangle());
                IVisualElementRenderer target;
                if (_rendererRef == null || !_rendererRef.TryGetTarget(out target))
                    return;
                target.NativeView.Frame = view.Bounds.ToRectangleF();
            }

            public override CGSize SizeThatFits(CGSize size)
            {
                IVisualElementRenderer target;
                if (!_rendererRef.TryGetTarget(out target))
                {
                    return base.SizeThatFits(size);
                }
                if (target.Element == null)
                    return CGSize.Empty;
                double width = size.Width;
                double heightConstraint = size.Height > 0 ? size.Height : double.PositiveInfinity;
                nfloat height = (float)target.Element.Measure(width, heightConstraint).Request.Height + (SupressSeparator ? 0.0f : 1f) / UIScreen.MainScreen.Scale;
                return new CGSize(size.Width, height);
            }

            protected override void Dispose(bool disposing)
            {
				IVisualElementRenderer renderer;
                if (disposing && _rendererRef != null && (_rendererRef.TryGetTarget(out renderer) && renderer.Element != null))
                {
					var platform = renderer.Element.GetPropertyValue<Platform>("Platform", BindingFlags.NonPublic);
                    platform?.CallMethod("DisposeModelAndChildrenRenderers", BindingFlags.NonPublic, renderer.Element);
                    _rendererRef = null;
                }
                base.Dispose(disposing);
            }

            IVisualElementRenderer GetNewRenderer()
            {
                IVisualElementRenderer renderer = Platform.CreateRenderer(_viewCell.View);
                _rendererRef = new WeakReference<IVisualElementRenderer>(renderer);
                ContentView.AddSubview(renderer.NativeView);
                return renderer;
            }

			void UpdateCell(MaterialViewCell cell)
            {
                ICellController viewCell = _viewCell;
                if (viewCell != null)
                    Device.BeginInvokeOnMainThread(viewCell.SendDisappearing);
                _viewCell = cell;
                Device.BeginInvokeOnMainThread(((ICellController)cell).SendAppearing);
				IVisualElementRenderer newRenderer;
                if (_rendererRef == null || !_rendererRef.TryGetTarget(out newRenderer))
                {
                    newRenderer = GetNewRenderer();
                }
                else
                {
                    if (newRenderer.Element != null && newRenderer == Platform.GetRenderer(newRenderer.Element))
                        newRenderer.Element.ClearValue(typeof(Platform).GetStaticFieldValue<BindableProperty>("RendererProperty", BindingFlags.NonPublic));

					Type handlerType = Registrar.Registered.GetHandlerType(this._viewCell.View.GetType());
					if (newRenderer.GetType() == handlerType || (newRenderer is VisualElementRenderer<VisualElement> && handlerType == null))
					{
						newRenderer.SetElement(_viewCell.View);
					}
					else
					{
						var platform = newRenderer.Element.GetPropertyValue<Platform>("Platform", BindingFlags.NonPublic);
						if (platform != null)
						{
							platform.CallMethod("DisposeRendererAndChildren", BindingFlags.NonPublic, newRenderer);
						}
						newRenderer = GetNewRenderer();
					}
                }
                Platform.SetRenderer(_viewCell.View, newRenderer);
            }
        }
    }
}